<?php

namespace Biz\Services\Site;

use Biz\Constants\Order\OrderConstants;
use Lumen\Logger\Logger;
use Illuminate\Http\Request;
use Biz\Models\Site\SiteOrder;
use Illuminate\Support\Facades\DB;
use Biz\Constants\Site\SiteOrderConstants;
use Biz\Criteria\Site\SiteFilterCriterion;
use Biz\Criteria\Site\UserFilterCriterion;
use Biz\Criteria\Site\LocaleFilterCriterion;
use Lumen\Core\Exceptions\BusinessException;
use Biz\Repositories\Site\SiteOrderRepository;
use Illuminate\Contracts\Pagination\Paginator;
use Biz\Criteria\Site\Order\OrderNoFilterCriterion;
use Biz\Criteria\Site\Order\RegistrationFeeFilterCriterion;
use Biz\Criteria\Site\Order\HotelReservationFilterCriterion;
use Biz\Repositories\Site\SiteOrderRegistrationFeeRepository;

/**
 * SiteOrderService.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class SiteOrderService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $registrationFeeRepository;

    /**
     * RepositoryController constructor.
     *
     * @param SiteOrderRepository                $repository
     * @param SiteOrderRegistrationFeeRepository $registrationFeeRepository
     */
    public function __construct(SiteOrderRepository $repository, SiteOrderRegistrationFeeRepository $registrationFeeRepository)
    {
        $this->repository                             = $repository;
        $this->registrationFeeRepository              = $registrationFeeRepository;
    }

    /**
     * 前台专用注册费用列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function getRegistrationFeeList(Request $request): Paginator
    {
        $user      = $request->user();
        $user_id   = $user->id;
        $site_id   = $request->get('site_id');
        $page_size = $request->get('page_size', 10);

        $results = $this->repository
            ->with('registration_fee')
            ->pushCriterion(new SiteFilterCriterion($site_id))
            ->pushCriterion(new UserFilterCriterion($user_id))
            ->pushCriterion(new RegistrationFeeFilterCriterion())
            ->paginate($page_size);

        return $results;
    }

    /**
     * 前台专用酒店注册列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function getHotelReservationList(Request $request): Paginator
    {
        $user      = $request->user();
        $user_id   = $user->id;
        $site_id   = $request->get('site_id');
        $page_size = $request->get('page_size', 10);

        $results = $this->repository
            ->with('hotel_reservation')
            ->pushCriterion(new SiteFilterCriterion($site_id))
            ->pushCriterion(new UserFilterCriterion($user_id))
            ->pushCriterion(new HotelReservationFilterCriterion())
            ->paginate($page_size);

        return $results;
    }

    /**
     * 列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function index(Request $request): Paginator
    {
        $order_id = $request->get('site_id');

        $results = $this->repository
            ->setCacheLifetime(0)
            ->pushCriterion(new SiteFilterCriterion($order_id))
            //->pushCriterion(new LocaleFilterCriterion())
            ->paginate(10);

        return $results;
    }

    /**
     * Find.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return SiteOrder
     */
    public function find(int $id): SiteOrder
    {
        $order = $this->repository->find($id);
        if (is_null($order)) {
            throw new BusinessException(trans('site/order/order.not_found'));
        }

        return $order;
    }

    /**
     * Find By uid.
     *
     * @param string $uid
     *
     * @throws BusinessException
     *
     * @return SiteOrder
     */
    public function findByUid(string $uid): SiteOrder
    {
        $id   = SiteOrder::decodeUid($uid);

        return $this->find($id);
    }

    /**
     * With find.
     *
     * @param int   $id
     * @param array $with
     *
     * @throws BusinessException
     *
     * @return SiteOrder
     */
    public function findWith(int $id, $with = []): SiteOrder
    {
        $order = $this->repository->with($with)->find($id);
        if (is_null($order)) {
            throw new BusinessException(trans('site/order/order.not_found'));
        }

        return $order;
    }

    /**
     * Find By Site Id.
     *
     * @param int $order_id
     *
     * @throws BusinessException
     *
     * @return bool
     */
    public function findBySiteId(int $order_id)
    {
        $order = $this->repository
            ->pushCriterion(new SiteFilterCriterion($order_id))
            ->findFirst();

        return $order;
    }

    /**
     * Find.
     *
     * @param string $order_no
     *
     * @throws BusinessException
     *
     * @return SiteOrder
     */
    public function findByOrderNo(string $order_no): SiteOrder
    {
        $order = $this->repository
            ->with(['user'])
            ->pushCriterion(new OrderNoFilterCriterion($order_no))
            ->findFirst();

        if (is_null($order)) {
            throw new BusinessException(trans('site/order/order.not_found'));
        }

        return $order;
    }

    /**
     * Store.
     *
     * @param Request $request
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function store(Request $request): SiteOrder
    {
        // Get Current User
        /** @var User $user */
        $user = $request->user();

        $data            = $request->all();
        $data['user_id'] = $user->id;

        return $this->create($data);
    }

    /**
     * Create.
     *
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function create(array $data): SiteOrder
    {
        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 创建订单
            $date     = date('Ymd');
            $time     = date('Hms');
            $order_no = sprintf('%s-%s-%s-%s', $date, config('payease.mid'), substr(microtime(), 2, 4), $time);

            $data['order_no'] = $order_no;
            $data['status']   = OrderConstants::STATUS_ORDER_CREATE;

            $order   = $this->repository->create($data);
            if (! $order) {
                throw new BusinessException(trans('site/order/order.create_fail'));
            }

//            // 订单详细
//            $type = $data['type'];
//
//            switch ($type) {
//                case SiteOrderConstants::TYPE_REGISTRATION_FEE:
//                    $data['registration_fee']['order_id'] = $order->id;
//                    $this->registrationFeeRepository->create($data['registration_fee']);
//                    $order->load('registration_fee');
//                    break;
//            }

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }

    /**
     * Detail.
     *
     * @param string $id
     *
     * @throws BusinessException
     *
     * @return SiteOrder
     */
    public function show(string $id): SiteOrder
    {
        $id    = SiteOrder::decodeUid($id);
        $order = $this->find($id);

        switch ($order->type) {
            case SiteOrderConstants::TYPE_REGISTRATION_FEE:
                $order->load('registration_fee');
                break;
            case SiteOrderConstants::TYPE_HOTEL_RESERVATION:
                $order->load('hotel_reservation');
                break;
        }

        return $order;
    }

    /**
     * Edit.
     *
     * @param string $id
     * @param array  $data
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function edit(string $id, array $data): SiteOrder
    {
        $id   = SiteOrder::decodeUid($id);

        return $this->update($id, $data);
    }

    /**
     * Update.
     *
     * @param int   $id
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function update(int $id, array $data): SiteOrder
    {
        $order = $this->find($id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $order   = $this->repository->update($order, $data);
            if (! $order) {
                throw new BusinessException(trans('site/order/order.create_fail'));
            }

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }

    /**
     * Remove.
     *
     * @param string $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function remove(string $id): bool
    {
        $id   = SiteOrder::decodeUid($id);

        return $this->delete($id);
    }

    /**
     * Delete.
     *
     * @param int $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(int $id): bool
    {
        /** @var SiteOrder $order */
        $order = $this->find($id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $this->repository->delete($order);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return true;
    }

    /**
     * Cancel.
     *
     * @param string $id
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function cancel(string $id): SiteOrder
    {
        /** @var SiteOrder $order */
        $order = $this->findByUid($id);

        // Check Status
        if (OrderConstants::STATUS_ORDER_CREATE !== $order->status) {
            throw new BusinessException(trans('site/order/order.cannot_cancel'));
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $order = $this->repository->update($order, [
                'status' => OrderConstants::STATUS_ORDER_CANCEL,
            ]);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }

    /**
     * Paying.
     *
     * @param SiteOrder $order
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function wait(SiteOrder $order): SiteOrder
    {
        // Check Status
        if (OrderConstants::STATUS_PAY_WAITING === $order->status) {
            return $order;
        }

        if (OrderConstants::STATUS_ORDER_CREATE !== $order->status) {
            throw new BusinessException(trans('site/order/order.cannot_pay'));
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $order = $this->repository->update($order, [
                'status' => OrderConstants::STATUS_PAY_WAITING,
            ]);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }

    /**
     * Paying.
     *
     * @param SiteOrder $order
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function paying(SiteOrder $order): SiteOrder
    {
        // Check Status
        if (OrderConstants::STATUS_PAY_ING === $order->status) {
            return $order;
        }

        if (OrderConstants::STATUS_PAY_WAITING !== $order->status) {
            throw new BusinessException(trans('site/order/order.cannot_pay'));
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $order = $this->repository->update($order, [
                'status' => OrderConstants::STATUS_PAY_ING,
            ]);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }

    /**
     * Failed.
     *
     * @param SiteOrder $order
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function failed(SiteOrder $order): SiteOrder
    {
        // Check Status
        if (OrderConstants::STATUS_PAY_ING !== $order->status) {
            throw new BusinessException('订单状态必须为支付中状态');
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $order = $this->repository->update($order, [
                'status' => OrderConstants::STATUS_PAY_FAILED,
            ]);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }

    /**
     * Success.
     *
     * @param SiteOrder $order
     *
     * @throws \Exception
     *
     * @return SiteOrder
     */
    public function success(SiteOrder $order): SiteOrder
    {
        // Check Status
        if (OrderConstants::STATUS_PAY_ING !== $order->status) {
            throw new BusinessException('订单状态必须为支付中状态');
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $order = $this->repository->update($order, [
                'status' => OrderConstants::STATUS_PAY_SUCCESS,
            ]);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $order;
    }
}
